package core;

import java.io.Serializable;
import view.GUI.LabelReader;

/**
 * An InPort is a port which retrieves values from a source-port (OutPort).
 *
 * @author Wijnand, modified by Ben
 */
public class InPort implements ValuePort, Serializable {
	private Class valueClass;
	private OutPort source = null;
	private TriggerPort sourceChanged = null;
        private Object defaultValue = null;

	public InPort(Class valueClass) {
		this(valueClass, null);
	}

	public InPort(Class valueClass, TriggerPort sourceChangedPort) {
		this.valueClass = valueClass;
		this.sourceChanged = sourceChangedPort;
	}

        public InPort(Class valueClass,TriggerPort sourceChangedPort, Object defaultValue) {
            this(valueClass,sourceChangedPort);
            this.defaultValue = defaultValue;
        }

        public InPort(Class valueClass,Object defaultValue){
            this(valueClass,null,defaultValue);
        }

	public Class getValueClass() { return valueClass; }

        public Object getDefaultValue(){
            return defaultValue;
        }

	/**
	 * @return the source-port which this InPort is retrieving values from,
	 * or null if this InPort is not connected to an OutPort.
	 */
	public OutPort getSource() { return source; }

	/**
	 * Connects this InPort to the given source (an OutPort), such that it will retrieve
	 * values from that source. If this InPort was previously connected
	 * to a different source, then that connection is lost.
	 * The parameter source can be null, in which case the InPort is "deconnected"
	 * from its former source.
	 * Note that the valueClass of the given source must be compatible with the InPort valueClass,
	 * otherwise a ConnectException is thrown.
	 * @param source new source InPort or null
	 * @throws ConnectException if the valueClass of the given source is not compatible with the valueClass of this InPort
	 */
	public void setSource(OutPort source) throws ConnectException
	{
		if (source!=null && !valueClass.isAssignableFrom(source.getValueClass()) ){
			throw new ConnectException(LabelReader.getInstance().getString("SourceNotCompatible")+": "+source.getValueClass() + " != " + valueClass);
                }
                this.source = source;
	}

	/**
	 * @return associated TriggerPort which handles changes of the source value,
	 * or null if no such TriggerPort is available.
	 * It is customary to propagate these triggers to any ports which depend
	 * on this InPort.
	 */
	public TriggerPort getSourceChangedPort() {
		return sourceChanged;
	}

	public void setSourceChangedPort(TriggerPort tp) {
		this.sourceChanged = tp;
	}

	/**
	 * Returns the value of the source port.
	 * @throws ConnectException if source not set
	 */
	public final Object getValue() throws ConnectException
	{
		Tracker.getInstance().valueRequested(this);
		if (this.source==null){
                    throw new ConnectException(LabelReader.getInstance().getString("SourceNotSet"));
                }
                source.setRequestPort(this);
		Object obj = this.source.getValue();
        
		Tracker.getInstance().valueReceived(this, obj);
		return obj;
	}
}

